namespace ScrumSprintMonitor.UI.Wpf.Converters
{
	#region #using Directives

	using System;
	using System.Windows.Media;

	using Infrastructure;
	using Infrastructure.Configuration;

	#endregion

	public static class RemainingWorkStatusColorHelper
	{
		public static Color GetColor(RemainingWorkStatus status, double ratio, string parameter, IPresentationConfiguration presentationConfiguration)
		{
			if (presentationConfiguration == null)
			{
				throw new ArgumentNullException("presentationConfiguration");
			}

			var statusLower = status;
			var statusUpper = status;
			if (status < RemainingWorkStatus.Normal)
			{
				statusUpper = status + 1;
			}
			else if (status > RemainingWorkStatus.Normal)
			{
				statusLower = status - 1;
			}

			statusLower = CoerceStatus(statusLower);
			statusUpper = CoerceStatus(statusUpper);

			var colorRangeLower = GetColorFromPresentationConfig(parameter, statusLower, presentationConfiguration);
			var colorRangeUpper = GetColorFromPresentationConfig(parameter, statusUpper, presentationConfiguration);

			var configuration = presentationConfiguration.GetRemainingWorkStatusPresentationConfig(status);
			double deviation;
			if (double.IsPositiveInfinity(configuration.UpperLimit) || double.IsInfinity(ratio))
			{
				deviation = 1.0;
			}
			else if (double.IsNaN(ratio))
			{
				deviation = 0.0;
			}
			else
			{
				deviation = (ratio - configuration.LowerLimit) / (configuration.UpperLimit - configuration.LowerLimit);
			}

			var color = Color.FromArgb((byte) (colorRangeLower.A + (colorRangeUpper.A - colorRangeLower.A) * deviation),
			                           (byte) (colorRangeLower.R + (colorRangeUpper.R - colorRangeLower.R) * deviation),
			                           (byte) (colorRangeLower.G + (colorRangeUpper.G - colorRangeLower.G) * deviation),
			                           (byte) (colorRangeLower.B + (colorRangeUpper.B - colorRangeLower.B) * deviation));

			return color;
		}

		private static RemainingWorkStatus CoerceStatus(RemainingWorkStatus status)
		{
			if (status <= RemainingWorkStatus.SeverelyUnderassigned)
			{
				status = RemainingWorkStatus.SeverelyUnderassigned;
			}
			if (status >= RemainingWorkStatus.SeverelyOverassigned)
			{
				status = RemainingWorkStatus.SeverelyOverassigned;
			}
			return status;
		}

		private static Color GetColorFromPresentationConfig(object parameter, RemainingWorkStatus status,
		                                                    IPresentationConfiguration presentationConfiguration)
		{
			if (presentationConfiguration == null)
			{
				throw new ArgumentNullException("presentationConfiguration");
			}

			var configuration = presentationConfiguration.GetRemainingWorkStatusPresentationConfig(status);

			switch ((string) parameter)
			{
				case "Background":
					return configuration.BackgroundColor;
				case "Foreground":
					return configuration.ForegroundColor;
				default:
					throw new ArgumentException("parameter");
			}
		}
	}
}